﻿// Decompiled with JetBrains decompiler
// Type: Unity.Netick.CodeGen.UnityCodeGen
// Assembly: Unity.Netick.CodeGen, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 8B3B8749-9F65-48DA-BE6F-84634E89AC85
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Editor\Unity.Netick.CodeGen.dll

using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using Netick;
using Netick.CodeGen;
using Netick.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity.CompilationPipeline.Common.Diagnostics;
using UnityEngine;

#nullable disable
namespace Unity.Netick.CodeGen;

public class UnityCodeGen : ICodeGenUser
{
  private MethodReference UnityUtils_GetSmoothInt;
  private MethodReference UnityUtils_GetSmoothBool;
  private MethodReference UnityUtils_GetSmoothNetworkBool;
  private MethodReference UnityUtils_GetSmoothAngle;
  private MethodReference UnityUtils_GetSmoothDouble;
  private MethodReference UnityUtils_GetSmoothFloat;
  private MethodReference UnityUtils_GetSmoothVector3;
  private MethodReference UnityUtils_GetSmoothVector2;
  private MethodReference UnityUtils_GetSmoothQuaternion;
  private MethodReference UnityUtils_GetSmoothColor;
  private MethodReference UnityUtils_GetFloat;
  private MethodReference UnityUtils_GetVector3;
  private MethodReference UnityUtils_GetVector2;
  private MethodReference UnityUtils_GetQuaternion;
  private MethodReference UnityUtils_GetColor;
  private MethodReference UnityUtils_SetFloat;
  private MethodReference UnityUtils_SetVector3;
  private MethodReference UnityUtils_SetVector2;
  private MethodReference UnityUtils_SetQuaternion;
  private MethodReference UnityUtils_SetColor;
  private MethodReference SerializeFieldAttributeCtor;
  private MethodReference HideInInspectorCtor;
  private MethodReference NetworkBehaviour_FindInterpolator;
  private MethodReference EngineGetter;
  private FieldReference SRef;
  private System.Type NetworkBehaviourType;
  private List<DiagnosticMessage> Diagnostics;

  public void Init(ModuleDefinition typeDefinition, List<DiagnosticMessage> diagnostics)
  {
    this.Diagnostics = diagnostics;
    this.NetworkBehaviourType = typeof (NetworkBehaviour);
    this.EngineGetter = typeDefinition.ImportReference((MethodBase) typeof (INetickScript).GetProperty("Engine").GetMethod);
    this.UnityUtils_GetSmoothInt = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothInt"));
    this.UnityUtils_GetSmoothBool = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothBool"));
    this.UnityUtils_GetSmoothNetworkBool = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothNetworkBool"));
    this.UnityUtils_GetSmoothAngle = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothAngle"));
    this.UnityUtils_GetSmoothDouble = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothDouble"));
    this.UnityUtils_GetSmoothFloat = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothFloat"));
    this.UnityUtils_GetSmoothVector3 = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothVector3"));
    this.UnityUtils_GetSmoothVector2 = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothVector2"));
    this.UnityUtils_GetSmoothQuaternion = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothQuaternion"));
    this.UnityUtils_GetSmoothColor = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetSmoothColor"));
    this.UnityUtils_GetFloat = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetFloat"));
    this.UnityUtils_GetVector3 = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetVector3"));
    this.UnityUtils_GetVector2 = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetVector2"));
    this.UnityUtils_GetQuaternion = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetQuaternion"));
    this.UnityUtils_GetColor = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("GetColor"));
    this.UnityUtils_SetFloat = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("SetFloat"));
    this.UnityUtils_SetVector3 = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("SetVector3"));
    this.UnityUtils_SetVector2 = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("SetVector2"));
    this.UnityUtils_SetQuaternion = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("SetQuaternion"));
    this.UnityUtils_SetColor = typeDefinition.ImportReference((MethodBase) typeof (NetickUnityUtils).GetMethod("SetColor"));
    this.NetworkBehaviour_FindInterpolator = typeDefinition.ImportReference((MethodBase) typeof (NetworkBehaviour).GetMethod("FindInterpolator"));
    this.SRef = typeDefinition.ImportReference(typeof (NetworkBehaviour).GetField("StatePtr"));
    this.SerializeFieldAttributeCtor = typeDefinition.ImportReference((MethodBase) typeof (SerializeField).GetConstructor(System.Type.EmptyTypes));
    this.HideInInspectorCtor = typeDefinition.ImportReference((MethodBase) typeof (HideInInspector).GetConstructor(System.Type.EmptyTypes));
  }

  public void Init(ModuleDefinition typeDefinition)
  {
  }

  public string GetNetworkScriptTypeFullName() => this.NetworkBehaviourType.FullName;

  public void Log(object msg) => Debug.Log(msg);

  public void LogWarning(object msg) => this.Diagnostics.AddWarning(msg.ToString());

  public void LogError(object error) => this.Diagnostics.AddError(error.ToString());

  int ICodeGenUser.GetAutoSmoothableVectorFloatFieldsCount(PropertyDefinition property)
  {
    if (((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (float).FullName)
      return 1;
    if (((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Vector3).FullName)
      return 3;
    if (((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Vector2).FullName)
      return 2;
    return ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Quaternion).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Color).FullName ? 4 : 0;
  }

  public bool IsPropertyAutoSmoothable(PropertyDefinition property)
  {
    return ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (int).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (bool).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (NetworkBool).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Angle).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (float).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (double).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Vector3).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Vector2).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Quaternion).FullName || ((MemberReference) ((PropertyReference) property).PropertyType).FullName == typeof (Color).FullName;
  }

  public void HandleAutoSmoothablePropertyGetter(
    MethodDefinition getMeth,
    PropertyDefinition item,
    TypeDefinition typeDefinition,
    MethodReference ptr,
    int offsetInWords,
    float precision,
    FieldDefinition interpolator,
    InterpolationSource interpolationSource)
  {
    ILProcessor ilProcessor = getMeth.Body.GetILProcessor();
    Collection<Instruction> instructions = getMeth.Body.Instructions;
    instructions.Clear();
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Callvirt, this.EngineGetter));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Callvirt, ptr));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I8, (long) offsetInWords));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_I));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4_4));
    instructions.Add(ilProcessor.Create(OpCodes.Mul));
    instructions.Add(ilProcessor.Create(OpCodes.Add));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldflda, (FieldReference) interpolator));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, (int) interpolationSource));
    this.InsertGetSmoothCall(((PropertyReference) item).PropertyType, instructions, ilProcessor);
    instructions.Add(ilProcessor.Create(OpCodes.Ret));
  }

  public void AddAutoSmoothableInitInstructions(
    MethodDefinition initMethod,
    PropertyDefinition property,
    FieldDefinition interpolator)
  {
    ILProcessor ilProcessor = initMethod.Body.GetILProcessor();
    Collection<Instruction> instructions = initMethod.Body.Instructions;
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldstr, ((MemberReference) property).Name));
    instructions.Add(ilProcessor.Create(OpCodes.Call, this.NetworkBehaviour_FindInterpolator));
    instructions.Add(ilProcessor.Create(OpCodes.Stfld, (FieldReference) interpolator));
  }

  public void OnPropertyFinishProcessing(
    PropertyDefinition property,
    FieldReference backFieldResolved)
  {
    FieldDefinition fieldDefinition = backFieldResolved.Resolve();
    if (((IEnumerable<CustomAttribute>) fieldDefinition.CustomAttributes).Where<CustomAttribute>((Func<CustomAttribute, bool>) (itemx => ((MemberReference) itemx.AttributeType).FullName == typeof (SerializeField).FullName)).FirstOrDefault<CustomAttribute>() == null)
      fieldDefinition.CustomAttributes.Add(new CustomAttribute(this.SerializeFieldAttributeCtor));
    fieldDefinition.CustomAttributes.Add(new CustomAttribute(this.HideInInspectorCtor));
  }

  public void OnArrayFinishProcessing(FieldDefinition arrayField)
  {
    if (((IEnumerable<CustomAttribute>) arrayField.CustomAttributes).Where<CustomAttribute>((Func<CustomAttribute, bool>) (itemx => ((MemberReference) itemx.AttributeType).FullName == typeof (HideInInspector).FullName)).FirstOrDefault<CustomAttribute>() != null)
      return;
    arrayField.CustomAttributes.Add(new CustomAttribute(this.HideInInspectorCtor));
  }

  public bool IsPropertyCompressable(TypeDefinition property, float precision)
  {
    return (double) precision != -1.0 && (((MemberReference) property).FullName == typeof (float).FullName || ((MemberReference) property).FullName == typeof (Vector3).FullName || ((MemberReference) property).FullName == typeof (Vector2).FullName || ((MemberReference) property).FullName == typeof (Quaternion).FullName || ((MemberReference) property).FullName == typeof (Color).FullName);
  }

  public void OverrideCompressablePropertyGetter(
    MethodDefinition getMeth,
    PropertyDefinition item,
    FieldReference backField,
    TypeDefinition typeDefinition,
    MethodReference ptr,
    int offsetInWords,
    float precision,
    bool ensureSafety)
  {
    ILProcessor ilProcessor = getMeth.Body.GetILProcessor();
    Collection<Instruction> instructions = getMeth.Body.Instructions;
    instructions.Clear();
    NetickILProcessor.AddGetterCheck(ensureSafety, getMeth, backField, ptr);
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Callvirt, ptr));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I8, (long) offsetInWords));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4_4));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_I8));
    instructions.Add(ilProcessor.Create(OpCodes.Mul));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_I));
    instructions.Add(ilProcessor.Create(OpCodes.Add));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_R4, precision));
    this.InsertReadCompressed(((PropertyReference) item).PropertyType, instructions, ilProcessor);
    instructions.Add(ilProcessor.Create(OpCodes.Ret));
  }

  public void OverrideStructCompressedPropertyGetter(
    TypeDefinition typeDefinition,
    MethodDefinition method,
    PropertyDefinition property,
    FieldDefinition backedField,
    float precision)
  {
    ILProcessor ilProcessor = method.Body.GetILProcessor();
    Collection<Instruction> instructions = method.Body.Instructions;
    instructions.Clear();
    ilProcessor.Body.Variables.Add(new VariableDefinition((TypeReference) new PinnedType((TypeReference) new PointerType(((FieldReference) backedField).FieldType))));
    ilProcessor.Body.InitLocals = true;
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldflda, (FieldReference) backedField));
    instructions.Add(ilProcessor.Create(OpCodes.Stloc_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldloc_0));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_U));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_R4, precision));
    this.InsertReadCompressed(((PropertyReference) property).PropertyType, instructions, ilProcessor);
    instructions.Add(ilProcessor.Create(OpCodes.Ret));
  }

  public void OverrideStructCompressedPropertySetter(
    TypeDefinition typeDefinition,
    MethodDefinition method,
    PropertyDefinition property,
    FieldDefinition backedField,
    float inversePrecision)
  {
    ILProcessor ilProcessor = method.Body.GetILProcessor();
    Collection<Instruction> instructions = method.Body.Instructions;
    instructions.Clear();
    ilProcessor.Body.Variables.Add(new VariableDefinition((TypeReference) new PinnedType((TypeReference) new PointerType(((FieldReference) backedField).FieldType))));
    ilProcessor.Body.InitLocals = true;
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldflda, (FieldReference) backedField));
    instructions.Add(ilProcessor.Create(OpCodes.Stloc_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldloc_0));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_U));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_1));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_R4, inversePrecision));
    this.InsertWriteCompressed(((PropertyReference) property).PropertyType, instructions, ilProcessor);
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4_0));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_U));
    instructions.Add(ilProcessor.Create(OpCodes.Stloc_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ret));
  }

  public void OverrideCompressablePropertySetter(
    MethodDefinition setMeth,
    PropertyDefinition item,
    FieldReference backingField,
    TypeDefinition typeDefinition,
    MethodReference ptr,
    MethodReference dirtfy,
    int offsetInWords,
    int sizeInWords,
    int is64,
    bool hasOnChanged,
    float precision)
  {
    ILProcessor ilProcessor = setMeth.Body.GetILProcessor();
    Collection<Instruction> instructions = setMeth.Body.Instructions;
    instructions.Clear();
    precision = (float) Math.Pow(10.0, (double) WeaverUtils.GetDecimals((Decimal) precision));
    Instruction instruction = ilProcessor.Create(OpCodes.Ldarga_S, (byte) 1);
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Callvirt, ptr));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, 0));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_U));
    instructions.Add(ilProcessor.Create(OpCodes.Bne_Un, instruction));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_1));
    instructions.Add(ilProcessor.Create(OpCodes.Stfld, backingField));
    instructions.Add(ilProcessor.Create(OpCodes.Ret));
    instructions.Add(instruction);
    instructions.Add(ilProcessor.Create(OpCodes.Conv_U));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_1));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_R4, precision));
    this.InsertWriteCompressed(((PropertyReference) item).PropertyType, instructions, ilProcessor);
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarga_S, (byte) 1));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_U));
    instructions.Add(ilProcessor.Create(OpCodes.Ldarg_0));
    instructions.Add(ilProcessor.Create(OpCodes.Callvirt, ptr));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, offsetInWords));
    instructions.Add(ilProcessor.Create(OpCodes.Conv_I));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4_4));
    instructions.Add(ilProcessor.Create(OpCodes.Mul));
    instructions.Add(ilProcessor.Create(OpCodes.Add));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, sizeInWords));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, hasOnChanged ? 1 : 0));
    instructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, is64));
    instructions.Add(ilProcessor.Create(OpCodes.Call, dirtfy));
    instructions.Add(ilProcessor.Create(OpCodes.Ret));
  }

  internal void InsertGetSmoothCall(
    TypeReference proType,
    Collection<Instruction> instructions,
    ILProcessor il)
  {
    switch (((MemberReference) proType).Name)
    {
      case "Single":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothFloat));
        break;
      case "Double":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothDouble));
        break;
      case "Vector3":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothVector3));
        break;
      case "Vector2":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothVector2));
        break;
      case "Quaternion":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothQuaternion));
        break;
      case "Color":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothColor));
        break;
      case "Int32":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothInt));
        break;
      case "Boolean":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothBool));
        break;
      case "NetworkBool":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothNetworkBool));
        break;
      case "Angle":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetSmoothAngle));
        break;
    }
  }

  internal void InsertReadCompressed(
    TypeReference proType,
    Collection<Instruction> instructions,
    ILProcessor il)
  {
    switch (((MemberReference) proType).Name)
    {
      case "Single":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetFloat));
        break;
      case "Vector3":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetVector3));
        break;
      case "Vector2":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetVector2));
        break;
      case "Quaternion":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetQuaternion));
        break;
      case "Color":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_GetColor));
        break;
    }
  }

  internal void InsertWriteCompressed(
    TypeReference proType,
    Collection<Instruction> instructions,
    ILProcessor il)
  {
    switch (((MemberReference) proType).Name)
    {
      case "Single":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_SetFloat));
        break;
      case "Vector3":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_SetVector3));
        break;
      case "Vector2":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_SetVector2));
        break;
      case "Quaternion":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_SetQuaternion));
        break;
      case "Color":
        instructions.Add(il.Create(OpCodes.Call, this.UnityUtils_SetColor));
        break;
    }
  }
}
